﻿#include <stdint.h>
#include <inttypes.h>
#include <signal.h>
#include <iostream>
#include <stdexcept>
#include <sstream>

#include <thrift/concurrency/ThreadFactory.h>
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/transport/TSSLServerSocket.h>
#include <thrift/transport/TSSLSocket.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include "FirstService.h"

using namespace std;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;
using namespace thrift::test;

apache::thrift::concurrency::Monitor gMonitor;
void signal_handler(int signum)
{
    if (signum == SIGINT)
    {
        gMonitor.notifyAll();
    }
}

class TestHandler : public FirstServiceIf
{
public:
    TestHandler() = default;

    void testString(string& out, const string& thing) override
    {
        printf("testString(\"%s\")\n", thing.c_str());
        out = thing;
    }
};

int main(int argc, char** argv)
{
    std::string sServerCRT = "cert.v3/server.crt";
    std::string sServerKEY = "cert.v3/server.key";

    // Dispatcher
    TBinaryProtocolFactoryT<TBufferBase>* binaryProtocolFactory = new TBinaryProtocolFactoryT<TBufferBase>();
    binaryProtocolFactory->setContainerSizeLimit(0);
    binaryProtocolFactory->setStringSizeLimit(0);

    std::shared_ptr<TProtocolFactory> protocolFactory;
    protocolFactory.reset(binaryProtocolFactory);

    // Processors
    std::shared_ptr<TestHandler> testHandler(new TestHandler());
    std::shared_ptr<TProcessor>  testProcessor(new FirstServiceProcessor(testHandler));

    // Transport
    std::shared_ptr<TSSLSocketFactory> sslSocketFactory;
    sslSocketFactory = std::shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
    sslSocketFactory->loadCertificate(sServerCRT.c_str());
    sslSocketFactory->loadPrivateKey(sServerKEY.c_str());
    sslSocketFactory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");

    std::shared_ptr<TServerSocket> serverSocket;
    serverSocket = std::shared_ptr<TServerSocket>(new TSSLServerSocket(9090, sslSocketFactory));

    // Factory
    std::shared_ptr<TTransportFactory> transportFactory;
    transportFactory = std::make_shared<TBufferedTransportFactory>();

    // Server Info
    cout << "Starting simple server (buffered/binary) listen on: " << serverSocket->getPort() << endl;

    // Server
    std::shared_ptr<apache::thrift::server::TServer> server;
    server.reset(new TSimpleServer(testProcessor, serverSocket, transportFactory, protocolFactory));

    if (server.get() != nullptr)
    {
        apache::thrift::concurrency::ThreadFactory factory;
        factory.setDetached(false);
        std::shared_ptr<apache::thrift::concurrency::Runnable> serverThreadRunner(server);
        std::shared_ptr<apache::thrift::concurrency::Thread>   thread = factory.newThread(serverThreadRunner);

        signal(SIGINT, signal_handler);

        thread->start();
        gMonitor.waitForever(); // wait for a shutdown signal

        signal(SIGINT, SIG_DFL);

        server->stop();
        thread->join();
        server.reset();
    }

    cout << "done." << endl;

    return 0;
}
